//
//  Etat.cpp
//  Taquin
//
//  Created by Benjamin Bouachour on 13/08/11.
//  Copyright 2011 Epitech. All rights reserved.
//

#include "Etat.h"

Etat::Etat()
{
 //   listAdjacence = ListAdjacence();
    blank_coord = pair<int, int>(-1, -1);
    voisins = evoisins();
    parent = NULL;
    qualite = -1;
    taquinGrid = tgrid();
    error = NULL;
    size = sqrtf(taquinGrid.size());

    parent = NULL;

}

Etat::Etat(const Etat *etat)// :blank_coord(etat.blank_coord), voisins(etat.voisins), 
                            //qualite(etat.qualite), taquinGrid(etat.taquinGrid), size(etat.size), error(NULL)
{
        if (etat == NULL)
            return;
//    listAdjacence = etat.listAdjacence;
    blank_coord = etat->blank_coord;
    voisins = etat->voisins;
//    if (this->parent) {
//        delete this->parent;
//        this->parent = NULL;
//    }
//    if (etat->parent != NULL)
//        this->parent = new Etat(etat->parent);
//    else
//       this->parent = NULL;
    this->parent = etat->parent;
    qualite = etat->getQualite();
    taquinGrid = etat->taquinGrid;
    size = sqrtf(taquinGrid.size());

    error = NULL;
}

//Etat::Etat(ListAdjacence &list): listAdjacence(list)
//{
//    taquinGrid = tgrid();
//    parent = NULL;
//    qualite = 0;
//    error = NULL;
//}

Etat::Etat(Etat *_parent, const tgrid &grid) :taquinGrid(grid)
{
//    listAdjacence = ListAdjacence(); 
    parent = _parent;
    voisins = evoisins();
    qualite = -1;
    error = NULL;
    blank_coord = pair<int, int>(-1, -1);
    size = sqrtf(taquinGrid.size());
}

Etat::Etat(const tgrid &grid): taquinGrid(grid)
{
    parent = NULL;
    qualite = -1;
    voisins = evoisins();
  //  listAdjacence = ListAdjacence(); 
    error = NULL;
    blank_coord = pair<int, int>(-1, -1);
    size = sqrtf(taquinGrid.size());

}

const bool Etat::operator==(const Etat& o)
{
    return o.taquinGrid == this->taquinGrid;
}


Etat & Etat::operator=(const Etat& o)
{
    
    
 //   this->listAdjacence =  o.listAdjacence;
    blank_coord = o.blank_coord;
    voisins = o.voisins;
//    if (this->parent) {
//        delete this->parent;
//        this->parent = NULL;
//    }
//    if (o.parent != NULL)
//        parent = new Etat(*(o.parent));
//    else
//        parent = NULL;
    parent = o.parent;
    qualite = o.qualite;
    taquinGrid = o.taquinGrid;
    size = o.size;
    error = NULL;
    return *this;
}

Etat::~Etat()
{
    if (error != NULL)
        delete error;
    evoisins::iterator it;
    for (it = voisins.begin(); it != voisins.end(); ++it)
        delete it->second;
}

const void Etat::fillListVoisins()
{
    if (taquinGrid.empty()) {
        if (error == NULL)
            error = new string("");
        throw error->append("dans fillListAdjacence(), list == empty\n");
    }
    else
        this->constructList();
}

const void Etat::fillListVoisins(const tgrid &grid)
{
    if (grid != taquinGrid)
        this->setGrid(grid);
    if (error == NULL)
        error = new string("on passe dans dans fillListdjacence\n");
    this->fillListVoisins();
}

const int &Etat::getQualite() const
{
    return qualite;
}

const void Etat::setQualite(const int &_qualite)
{
    qualite = _qualite;
}

const int &Etat::getCost() const
{
    return c;
}

const void Etat::setCost(const int &_qualite)
{
    c = _qualite;
}

const int &Etat::getDistance() const
{
    return d;
}

const void Etat::setDistance(const int &_qualite)
{
    d = _qualite;
}


const Etat *Etat::getParent() const
{
    return parent;
}

const void Etat::setParent(Etat *_parent)
{
//    if (parent)
//        delete parent;
    parent = _parent;
}

const evoisins &Etat::getListVoisins()const
{
    return voisins;
}

const void Etat::setListVoisins(const evoisins &list)
{
    voisins = list;
}

const tgrid &Etat::getGrid()const
{
    return taquinGrid;
}

const void Etat::setGrid(const tgrid &list)
{
    taquinGrid = list;
    size = sqrtf(taquinGrid.size());
}


const pair<int, int> &Etat::getBlank() const
{
    return blank_coord;
}



const void Etat::searchBlank()
{
    tgrid::const_iterator it;
    for(it = taquinGrid.begin(); it != taquinGrid.end(); ++it)
    {
        if (it->second.compare(BLANK_CHAR) == 0)
        {
            blank_coord = it->first;
            return;
        }
    }
    if (error == NULL)
        error = new string("");
    error->append("No blank case in taquin");
    throw error;
}

const void Etat::constructList()
{
    AffResult aff;
    if (blank_coord.first == -1 || blank_coord.second == -1)
        this->searchBlank();
    if (blank_coord.first < size -1) 
    {
        tgrid newGrid = tgrid(taquinGrid);
        newGrid[pair<int, int>(blank_coord.first + 1, blank_coord.second)].swap(newGrid[blank_coord]);     
        Etat *right = new Etat(this, newGrid);
        right->blank_coord = pair<int, int>(blank_coord.first + 1, blank_coord.second);
        voisins[0] = right;
//        cout << "voisins de droite = " << endl;
//        aff.affEtat(right);
    }
    if (blank_coord.second < size -1)
    {
        tgrid newGrid = tgrid(taquinGrid);
        newGrid[pair<int, int>(blank_coord.first, blank_coord.second + 1)].swap(newGrid[blank_coord]);     
        Etat *down = new Etat(this, newGrid);
        down->blank_coord = pair<int, int>(blank_coord.first, blank_coord.second + 1);
        voisins[1] = down;
//        cout << "voisins de down = " << endl;
//        aff.affEtat(down);
    }
    if (blank_coord.first > 0)
    {
        tgrid newGrid = tgrid(taquinGrid);
        newGrid[pair<int, int>(blank_coord.first - 1, blank_coord.second)].swap(newGrid[blank_coord]);     
        Etat *left = new Etat(this, newGrid);
        left->blank_coord = pair<int, int>(blank_coord.first - 1, blank_coord.second);
        voisins[2] = left;
//        cout << "voisins de left = " << endl;
//        aff.affEtat(left);
    }
    if (blank_coord.second > 0)
    {
        tgrid newGrid = tgrid(taquinGrid);
        newGrid[pair<int, int>(blank_coord.first, blank_coord.second - 1)].swap(newGrid[blank_coord]);     
        Etat *up = new Etat(this, newGrid);
        up->blank_coord = pair<int, int>(blank_coord.first, blank_coord.second - 1);
        voisins[3] = up;
//        cout << "voisins de up = " << endl;
//        aff.affEtat(up);
    }
}

const int &Etat::getSize() const
{
    return size;
}

